﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Extensions;

namespace MetaSharp.Transformation.Tests.Patterns
{
    public class ErrorTests
    {
        [Fact]
        public async Task SingleValueMatchedProducesNoErrors()
        {
            var p = Pattern.ErrorUnless(Pattern.Value('a'));
            var m = await Pattern.Match(p, "a");
            Assert.Empty(m.Errors);
        }

        [Fact]
        public async Task SingleValueUnmatchedProducesError()
        {
            var p = Pattern.ErrorUnless(Pattern.Value('a'));
            var m = await Pattern.Match(p, "z");
            Assert.Equal(1, m.Errors.Length);
        }

        [Fact]
        public async Task SomeValuesMatchedProcudesError()
        {
            var p = Pattern.ErrorUnless(Pattern.And(Pattern.Value('a'), Pattern.Value('a')));
            var m = await Pattern.Match(p, "az");
            Assert.Equal(1, m.Errors.Length);
        }

        [Fact]
        public async Task OnlyUnmatchedPatternsProduceErrors()
        {
            var p1 = Pattern.ErrorUnless(Pattern.Value('a'));
            var p2 = Pattern.And(p1, p1);
            var m = await Pattern.Match(p2, "az");
            Assert.Equal(1, m.Errors.Single().Span.Start);
        }

        [Fact]
        public async Task ErrorUnlessConsumesNoInputWhenItFails()
        {
            var p = Pattern.ErrorUnless(Pattern.Value('a'));
            var m = await Pattern.Match(p, "z");
            Assert.Equal('z', m.End.Stream.Next().Current);
        }

        [Fact]
        public async Task UnexpectedValuesConsumesAllUntilEnd()
        {
            var p = Pattern.ErrorUntil(Pattern.Value('a'));
            var m = await Pattern.Match(p, "zzz");
            Assert.True(m.End.Stream.IsEmpty);
        }

        [Fact]
        public async Task UnexpectedValuesConsumedUntilExpectedValue()
        {
            var p = Pattern.ErrorUntil(Pattern.Value('a'));
            var m = await Pattern.Match(p, "za");
            var e = m.Errors.Single();
            Assert.Equal(SourceSpan.From(0, 1), e.Span);
        }

        [Fact]
        public async Task UnexpectedValuesSurroundedByExpectedValuesConsumed()
        {
            var p = Pattern.And(
                Pattern.Value('a'),
                Pattern.ErrorUntil(Pattern.Value('a')));
            var m = await Pattern.Match(p, "azzza");
            var e = m.Errors.Single();
            Assert.Equal(SourceSpan.From(1, 4), e.Span);
        }

        [Fact]
        public async Task UnexpectedValuesUntilEndConsumeAllInput()
        {
            var p = Pattern.And(
                Pattern.Value('a'),
                Pattern.ErrorUntil(Pattern.Value('a')));
            var m = await Pattern.Match(p, "azzz");
            Assert.True(m.End.Stream.IsEmpty);
        }
    }
}
